/*
** Copyright 2004 by Hellosoft Inc. All rights reserved. No part
** of this publication, or any software included with it, may be
** reproduced, stored in a retrieval system, or transmitted in
** any form or by any other means, including photocopying,
** electronic or mechanical recording or otherwise, without
** prior written permission of the copyright holder
**
** Hellosoft Confidential and Proprietary information
**
**-------------------------------------------------------------
**/

/************ System Header Files ***************/
#include <stdio.h>
#include <stdlib.h>

/************ Private Header Files **************/
#include "HsTypes.h"
#include "PhyDebug.h"
#include "PhyStruct.h"
#include "PmdGlobals.h"
#include "PhyConstants.h"
#include "tables.h"
#include "iqdma_3500.h"
#include "rx_functions.h"
#include "training.h"
#include "correlation.h"
#include "sync_correlation.h"
#include "sfd_header.h"
#include "rx1_functions.h"
#include "rx2_functions.h"
#include "rx55_functions.h"
#include "rx11_functions.h"
#include "equalizer.h"
#include "thread_globals.h"
//#include "rf_api.h"
#include "wlan_phy_mac.h"
//#include "wlan_const.h"

#include "wlan_mac.h"
#include "threads_common.h"//add 627

#ifdef RUN_ON_BOARD
#define PRINT_FN1	printf
#else
#define PRINT_FN1	__putstring
#endif

//#define TEST_TXT       1


volatile hs_int32_t phy_rx_tx_dacinit_flag;

volatile unsigned success_count[4] = {0,0,0,0};

struct HS_Phy11bStr  HS_Phy11bPtrGlobal;

extern volatile hs_int32_t rx_latency;

#ifndef TEST_TXT
/*Max Size is given to support all data rates */
hs_int16_t GPHY_asInputI[GLOBAL_BUF_SIZE_RX];
hs_int16_t GPHY_asInputQ[GLOBAL_BUF_SIZE_RX];
#else
/** Precomputed Preamble+SFD+header samples **/
hs_int16_t GPHY_asInputI[192*22] =
{
    #include "dataI_ref.h"
};

hs_int16_t GPHY_asInputQ[192*22] =
{
    #include "dataQ_ref.h"
};
#endif

hs_int16_t eq_pream_sfd_ref[PREAMBLE_DOWNSAMPLE_REFSIZE]; //1584*2

/*format ssSineTable A(0,15)*/
hs_int16_t ssCosineSineTable[513*2] ;
/* Fixed point Tan table*/
hs_uint8_t OneByXFormat[256];
hs_uint16_t OneByXTbl[256];

/* This table is having values of arctan(x).
* x is ranging from 0 --> 2 in steps of 1/64
* Format is U(1,15) */
hs_uint16_t usAtanTbl[256];

/* This table is having values of slopes of Atan
* for the same values of x for which arctan values
* are stored in above table. Format is U(0,16) */
hs_uint16_t usAtanSlope[256];

hs_int16_t BarkerScaled[32];

/* Symbol lock variables */
hs_int16_t   asSyncBufI[64];
hs_int16_t   asSyncBufQ[64];

hs_int16_t iq_scale[32];
hs_int16_t iq_bias[32];
hs_int32_t tic1=0;
hs_int32_t tic2=0;

volatile hs_uint32_t rx_status_global;
volatile hs_uint32_t rx_status_monitor;
Mac2PhyStruct mac2phy_struct;

void print_freqoffset(struct HS_Phy11bStr  *HS_Phy11bPtrTh1)
{
	double freq_offset;
	hs_int32_t freq_offset_int;
	hs_int32_t freq_offset_frac;

	freq_offset = (hs_int32_t)(HS_Phy11bPtrTh1->siPhaseUpdate*1e-3)*RX_FS/(1<<9)/(1<<22);
	freq_offset_int = (hs_int32_t)freq_offset;
	freq_offset_frac = (freq_offset/freq_offset_int)*1000;
	//__putstring("FREQUENCY OFFSET = %d.%d KHz\n", freq_offset_int, freq_offset_frac);
	printf("FREQUENCY OFFSET = %d.%d KHz\n", freq_offset_int, freq_offset_frac);
}

void phy_rx_init()
{
	hs_int32_t i;
	struct HS_Phy11bStr  *HS_Phy11bPtrTh1;

	for(i=0; i<PREAMBLE_DOWNSAMPLE_REFSIZE; i++){
		eq_pream_sfd_ref[i] = eq_preamble_sfd_ref_g[2*i]*EQ_REF_MULT;
	}

	for(i=0; i<32; i++){
    	iq_scale[i] = iq_scale_g[i];
    	iq_bias[i] = iq_bias_g[i];
    }
	printf("iq_scale=%d,iq_bias=%d,buf_size=%d\n",iq_scale_g[0],iq_bias[0],GLOBAL_BUF_SIZE_RX);

    for(i=0; i<513; i++){
        ssCosineSineTable[i] = ssCosineTable_g[i];
        ssCosineSineTable[513+i] = ssSineTable_g[i];
    }

    /* Check the A2D buffers' address alignment anyway */
    if( ((hs_int32_t)GPHY_asInputI & RF_SUBB_ALIGN) ||
       ((hs_int32_t)GPHY_asInputQ & RF_SUBB_ALIGN))
    {
       fprintf(stderr,"RF buffers not aligned\n");
       fprintf(stderr,"%p %p %d %d\n", GPHY_asInputI, GPHY_asInputQ,
                ((hs_int32_t)GPHY_asInputI & RF_SUBB_ALIGN),
                ((hs_int32_t)GPHY_asInputQ & RF_SUBB_ALIGN));
       exit (-27);
    }

    /** Copy sin/cos/tan tables **/
    for(i=0; i<256; i++){
        OneByXFormat[i] = OneByXFormat_g[i];
        OneByXTbl[i] = OneByXTbl_g[i];
        usAtanTbl[i] = usAtanTbl_g[i];
        usAtanSlope[i] = usAtanSlope_g[i];
    }

    HS_Phy11bPtrTh1 = &HS_Phy11bPtrGlobal;

    HS_Phy11bPtrTh1->rx_status_l = &rx_status_global;//add 627
	/** Copy all tables **/
	for(i=0; i<32; i++){
	   BarkerScaled[i] = asUpSampBarkerSeq_g[i] << 14;
	}

	HS_Phy11bPtrTh1->agcIndex = 30;//70;
	HS_Phy11bPtrTh1->iq_scale = iq_scale;
	HS_Phy11bPtrTh1->iq_bias = iq_bias;

	printf("Iaddr = %x, Qaddr = %x\n", GPHY_asInputI, GPHY_asInputQ);
	//printf("addr of success count = %x\n", success_count);

	init_global_buffers(HS_Phy11bPtrTh1);

	/** Init Equalizer buffers, variables **/
	eq_buffer_init(HS_Phy11bPtrTh1);

	init_rx(HS_Phy11bPtrTh1);
	init_thread_flags(HS_Phy11bPtrTh1);

	tx_rx_mode_2 = 0;
	tx_rx_mode_3 = 0;

	/** Signal all other threads: should init all before this **/
	threads_all_init_done = 1;
}


/** Main Thread **/
hs_int32_t Layer1Receive(hs_uint8_t *payload)
{
	int i;
	hs_int32_t rx_status;
	//hs_int32_t cnt = 0;
    hs_int32_t NSymbols=0;


    struct HS_Phy11bStr  *HS_Phy11bPtrTh1;
    ePHYSTATES_TH  ePhyState;
    ePHYSTATES_TH  ePhyState_Prev;  //test code

    HS_Phy11bPtrTh1 = &HS_Phy11bPtrGlobal;
    HS_Phy11bPtrTh1->rx_status_l = &rx_status_global;
    HS_Phy11bPtrTh1->pcPayloadByte = payload;
//    HS_Phy11bPtrTh1->agcIndex = 30;//70;

    /** RX starts **/
    init_rx(HS_Phy11bPtrTh1);
    init_thread_flags(HS_Phy11bPtrTh1);

    rx_status = HS_INCOMPLETE;
    PayloadLen = 0;
    rate_err = 0;

    /** Start the RF **/
//    if (!mac_config_g.rf_disabled){
//    	sblan_receive(); //start rf dev
//    }

    ePhyState = PHY_RX_INIT_TH;
    ePhyState_Prev = PHY_RX_INIT_TH;
    tx_rx_mode_2 = RX_MODE;
    tx_rx_mode_3 = RX_MODE;

    WRITE_STATUS(0x4080000C,0xAAAA);

    while(1)
    {
        switch(ePhyState)
        {
           case PHY_RX_INIT_TH:
           {
               START_CLOCK
               PRINT_CYCLES("init_rx");
               rx_status_monitor = 1;

               /**  Initializing for Circular buffers  **/
               ePhyState  = PHY_RX_DETECT_ENERGY_TH;
               break;
           }/* case PHY_RX_INIT_TH */

           case PHY_RX_DETECT_ENERGY_TH:
           {
               START_CLOCK

#ifndef TEST_TXT
               start_iqdma(HS_Phy11bPtrTh1, &GPHY_asInputI[0], &GPHY_asInputQ[0]);
#else
               HS_Phy11bPtrTh1->piRdPtrI    = &GPHY_asInputI[0];
               HS_Phy11bPtrTh1->piRdPtrQ    = &GPHY_asInputQ[0];
#endif

               PRINT_CYCLES("start_iqdma");
               rx_status_monitor = 2;
               wlan_do_ED(HS_Phy11bPtrTh1, &ePhyState);

               tic1 = __sb_cfsr(MACH_CYC);
               break;
           }/* case PHY_RX_DETECT_ENERGY_TH */

           case PHY_RX_CLIP_DETECTION_TH :
           {
        	   rx_status_monitor = 3;
        	   //wlan_do_AGC(HS_Phy11bPtrTh1, &ePhyState);
        	   wlan_do_AGC2(HS_Phy11bPtrTh1, &ePhyState);
               break;
           }/* case PHY_RX_CLIP_DETECTION_TH*/

           case PHY_RX_COARSE_SYNC_BUF_SYMB_TH :
           {
               /* Buffering two symbols for performing symbol boundary
                estimation. Storing I and Q samples into buffer */
        	   rx_status_monitor = 4;
               wlan_do_buffer_for_correlation(
                                HS_Phy11bPtrTh1,
                                asSyncBufI,
                                asSyncBufQ,
                                &ePhyState
                              );


               break;
           } /* case PHY_RX_COARSE_SYNC_BUF_SYMB_TH */

           case PHY_RX_COARSE_SYNC_CORR_TH:   //barker correlation
           {
        	   rx_status_monitor = 5;
        	   do_correlation_th1(
                        HS_Phy11bPtrTh1,
                        BarkerScaled,
                        asSyncBufI,
                        asSyncBufQ,
                        &ePhyState
                    );

               break;
           } /* case PHY_RX_COARSE_SYNC_CORR_TH*/

           case PHY_RX_GET_SYMBOL:
           {
        	   get_oldsymbol(HS_Phy11bPtrTh1);
               ePhyState = PHY_RX_EST_CARRIER_ERR_TH;
               break;
           }

           case PHY_RX_EST_CARRIER_ERR_TH:
           {
        	   rx_status_monitor = 6;
        	   get_carrier_symbols(HS_Phy11bPtrTh1, &ePhyState);

                START_CLOCK
                carrier_offset_est(HS_Phy11bPtrTh1, OneByXFormat, OneByXTbl, usAtanSlope, usAtanTbl);
                PRINT_CYCLES("carrier estimation");

                WRITE_STATUS(0x4080000C,0xBBBB);
                break;

           } /* case PHY_RX_EST_CARRIER_ERR_TH   */

           case PHY_RX_SYMBOL_LOCK_TH:
           {
                /** Frame sync with preamble **/
        	   //rx_status_global = 6;
                symbol_lock_th1(HS_Phy11bPtrTh1, &ePhyState, ssCosineSineTable);
                WRITE_STATUS(0x4080000C,0xCCCC);

                break;
           } /*PHY_RX_SYMBOL_LOCK_TH*/

          case PHY_RX_STATE_SFD_TH:
          {
        	    rx_status_monitor = 7;
        	    //printf("now rx_status_monitor is %d\n",rx_status_monitor);  //test code
        	    equalizer_pre(HS_Phy11bPtrTh1, ssCosineSineTable);
                wlan_sfd(HS_Phy11bPtrTh1, &ePhyState, ssCosineSineTable);

                WRITE_STATUS(0x4080000C,0xDDDD);

                break;
          }/* case PHY_STATE_SFD_TH */

          case PHY_RX_STATE_HEADER_TH:
          {
        	  rx_status_monitor = 8;
        	  wlan_do_header(HS_Phy11bPtrTh1, ssCosineSineTable);

              WRITE_STATUS(0x4080000C,0xEEEE);

              ePhyState  = (ePHYSTATES_TH)HS_Phy11bPtrTh1->ePhyState;

              NSymbols = HS_Phy11bPtrTh1->siNPayloadSym;

              WRITE_STATUS(0x4080000C,0xEEAA);

              break;
          }/* PHY_RX_STATE_HEADER_TH */


          case PHY_STATE_DM_ONEMBPS_TH:
          {
              wlan_do_1mbps(
                        HS_Phy11bPtrTh1,
                        &ePhyState,
                        NSymbols,
                        ssCosineSineTable
              );

              WRITE_STATUS(0x4080000C,0xEE11);

              break;
          }/* case PHY_STATE_DM_ONEMBPS_TH */

          case PHY_STATE_DM_TWOMBPS_TH:
          {
              wlan_do_2mbps(
                    HS_Phy11bPtrTh1,
                    &ePhyState,
                    NSymbols,
                    ssCosineSineTable
              );

              WRITE_STATUS(0x4080000C,0xEE22);

              break;
          }/* case PHY_STATE_DM_TWOMBPS_TH */

          case PHY_STATE_DM_FIVEDOTFIVE_TH:
          {
              wlan_do_55mbps(
                        HS_Phy11bPtrTh1,
                        &ePhyState,
                        NSymbols,
                        ssCosineSineTable
                    );

              WRITE_STATUS(0x4080000C,0xEE55);

                break;
          }/* case PHY_STATE_DM_FIVEDOTFIVE_TH */

          case PHY_STATE_DM_ELEVENMBPS_TH:
          {
              wlan_do_11mbps(
                        HS_Phy11bPtrTh1,
                        &ePhyState,
                        NSymbols,
                        ssCosineSineTable
                );

              WRITE_STATUS(0x4080000C,0xEE66);

              break;

          }/*case PHY_STATE_DM_ELEVENMBPS_TH*/

          case PHY_STATE_SWITCH_OFF_TH:
          {
        	  while(*HS_Phy11bPtrTh1->rx_status_l == HS_INCOMPLETE){
				 SPIN(4);
        	  }

              WRITE_STATUS(0x4080000C,0x7777);
              break;
          }/* case PHY_STATE_SWITCH_OFF_TH */

     }/* switch ePhyState */

	 if(*HS_Phy11bPtrTh1->rx_status_l != HS_INCOMPLETE){

		 WRITE_STATUS(0x4080000C,*HS_Phy11bPtrTh1->rx_status_l);

		 //find_latency(HS_Phy11bPtrTh1);

		 // TODO add wait status
		 //wlan_do_ED_thresh(HS_Phy11bPtrTh1);

		 stop_rxiqdma();
		 tic2 = __sb_cfsr(MACH_CYC);

		 /** Stop the RF **/
		 if (!mac_config_g.rf_disabled){
			 //sblan_receive_stop();
		 }

		 rx_status = *HS_Phy11bPtrTh1->rx_status_l;

		 #if 1
		 if(rx_status == HS_COMPLETE){

			 success_count[0]++;
			 //printf("%d SUCCESSFUL DECODING OF PACKET (len = %d), delay = %d\n", success_count[0],PayloadLen-4, rx_latency/44);
			 //__putstring("SUCCESSFUL DECODING OF PACKET (len = %d), delay = %d\n", PayloadLen-4, rx_latency/44);

			 /*
			 if(rate_err == 110){
				 PRINT_FN1("SUCCESSFUL DECODING OF PACKET (len = %d), delay = %d\n",
					 PayloadLen-4, rx_latency/44);
			 }
			 */
			 //PRINT_FN1("rate = %d\n", rate_err);

		 }
		 else if(rx_status ==  HS_ERROR){

			 success_count[1]++;
//			 printf("%d DECODING OF PACKET  FAILED\n",success_count[1]);
//			 printf("DECODING OF PACKET  FAILED(len = %d), delay = %d\n ", PayloadLen-4, rx_latency/44);
			 /*
			 PRINT_FN1("DECODING OF PACKET  FAILED(len = %d), delay = %d ",
					 PayloadLen-4, rx_latency/44);
			 PRINT_FN1("rate = %d\n", rate_err);
			 */
		 }
		 else if(rx_status == HS_HEAD_CRC_ERROR){
			 success_count[2]++;
//			 printf("%d HEAD_CRC_ERROR\n",success_count[2]);
//
//			 printf("HEAD CRC ERROR (len = %d), ", PayloadLen-4);
//			 printf("rate = %d\n", rate_err);

		 }
		 else{
			 success_count[3]++;
			 printf("rx_status = %d\n", rx_status);
		 }
		 #endif

		 //print_freqoffset(HS_Phy11bPtrTh1);
		 break;
	 }

//	 if(ePhyState !=ePhyState_Prev){
//		 printf("now the ePhyState is %d\n",ePhyState);
//		 ePhyState_Prev = ePhyState;
//	 }

  }/* While */

  WRITE_STATUS(0x4080000C,0xFFFF);

  return rx_status;
}

